import Q from "../lib/qunee-es";
import { PowerEditor } from "./PowerEditor";
import {createMap,MapGraph} from "./tools/MapGraph"

class PowerWsEditor extends PowerEditor {
	//options : {
	// url: ws://localhost:7002/ws/powernet/1
	// target: target div id ,eg. "canvas"
	// editable: true|false
	// }
	constructor(options) {
		super(options);
		this.afterLoad = null; // after send ws "graph_init" and load data to graph
		this.connect();
	}

	connect() {
		var self = this;
		this.powerWs = new PowerWs(this.options);
		this.setWsEvents();
		this.powerWs.onopen = function (evt) {
			self.afterWsOpen(evt);
		};
		this.powerWs.init();
	}
	setWsEvents() {
		var ws = this.powerWs;
		var self = this;
		ws.on("graph_init", function (subject, data) {
			self.onWsGraphInit(subject, data);
		});
		ws.on("graph_update", function (subject, data) {
			self.onWsGraphUpdate(subject, data);
		});
		ws.on("element_new", function (subject, data) {
			self.onWsElementNew(subject, data);
		});
		ws.on("element_delete", function (subject, data) {
			self.onWsElementDelete(subject, data);
		});
		ws.on("element_update_props", function (subject, data) {
			self.onWsNodeUpdateProps(subject, data);
		});
	}
	sendUpdateGraph(data) {
		this.powerWs.send("graph_update" , data)
	}
	sendCreateElement(protoId , props ,tempId) {
		props = props ||{}
		var parentId = this.currentSubNetworkId()
		var n = {
			TempId : tempId,
			Sender : this.uuid,
			ProtoId:  protoId,// should get from ui
			Props: props,
		};
		if (parentId) {
			n.Props.parent = parentId;
		}
		this.powerWs.send("element_new", n);
	}
	//必须实现
	sendCreateElementByNode(node) {
		console.log("sendCreateElement", node);
		var parentId = this.currentSubNetworkId(); //子网
		var n = {
			ProtoId:  1,// should get from ui
			Props: {},
		};
		if (parentId) {
			n.Props.parent = parentId;
		}
		if (node instanceof Q.Node) {
			n.ProtoId = 1; //demo
			n.Props.x = parseInt(node.x);
			n.Props.y = parseInt(node.y);
		}

		if (node instanceof Q.Edge) {
			n.ProtoId = 2; //demo
			n.Props.from = node.from * 1;
			n.Props.to = node.to * 1;
		}
		this.powerWs.send("element_new", n);
	}
	sendDeleteElement(ids) {
		console.log("sendDeleteElement", ids);
		this.powerWs.send("element_delete", { Ids: ids });
	}
	sendUpdateElement(props) {
		console.log("sendUpdateElement", props);
		props.Sender = this.uuid
		this.powerWs.send("element_update_props", props);
	}
	//链接ws完成之后
	afterWsOpen(evt) {
		this.powerWs.send("graph_init");
	}

	// websocket init event callback
	onWsGraphInit(subject, data) {
		if (!data) {
			return;
		}
		this.graphInfo = data.Graph
		var props = this.graphInfo.Props

		if(props.map) {
			var m = createMap({target:this.options.target ,lat:props.x, lng:props.y, zoom:props.zoom })
			this.setGraph(new MapGraph(m))
		}else {
			this.setGraph(new Q.Graph(this.options.target))
			this.graph.originAtCenter = false;
		}
		this.clear();
		this.initEditor()
		this.loadElements(data.Elements);
		this.initProtoBar(data.Protos)
		this.initPropBar()
		if (this.afterLoad) {
			this.afterLoad();
		}
	}
	initProtoBar(protoClasses) {
		this.protoBar.initProtos(protoClasses)
	}
	initPropBar() {
		this.propBar.show(this.graph)
	}
	onWsGraphUpdate(subject, data) {
		Object.assign(this.graphInfo, data)
	}
	onWsElementNew(subject, data) {
		var temp = this.tempElements[data.TempId]
		if(temp) {
			this.graph.removeElement(temp)
		}
		this.graph.callLater(()=> {
			this.createElement(data.Element , data.TempId, data.Sender);
		})
	}
	onWsElementDelete(subject, data) {
		for (var i in data.Ids) {
			this.removeElement(data.Ids[i]);
		}
	}
	onWsNodeUpdateProps(subject, data) {
		var ele = this.getElement(data.Id);
		ele.set("sender", data.Sender);
		var skipProps = { x: true, y: true}
		var props = data.Props
		this.setProps(ele, props,skipProps);
		if ('x' in props) {
			this.setLocation(ele,props.x , props.y)
		}
	}
}

class PowerWs {
	constructor(options) {
		this.options = options;
		this.cbs = {}; //msg callbacks
		this.ws = null;
		this.onopen = null;
		this.onclose = null;
		this.onerror = null;
	}
	send(subject, data) {
		this.ws.send(
			JSON.stringify({
				Subject: subject,
				Data: data,
			})
		);
	}
	on(subject, cb) {
		this.cbs[subject] = cb;
	}
	reconnect() {
		if (this.ws) {
			try {
				this.ws.close();
			} catch (e) {
				console.log(e);
			}
		}
		this.init();
	}

	init() {
		this.ws = new WebSocket(this.options.url);
		var self = this;
		var ws = this.ws;

		ws.onmessage = function (evt) {
			console.log("ws.onmessage", evt.data);
			var msg = JSON.parse(evt.data);
			var cb = self.cbs[msg.Subject];
			if (cb) {
				cb(msg.Subject, msg.Data);
			} else {
				console.log("warning: on callback from ws message ", evt.data);
			}
		};

		ws.onopen = function (evt) {
			console.log("ws.onopen", evt);
			if (self.onopen) {
				self.onopen(evt);
			}
		};

		ws.onclose = function (evt) {
			console.log("ws.onclose", evt);
			if (self.onclose) {
				self.onclose(evt);
			}
		};
		ws.onerror = function (evt) {
			console.log("ws.onerror", evt);
			if (self.onerror) {
				self.onerror(evt);
			}
		};
	}
}

export { PowerWsEditor, PowerWs };
window.PowerWsEditor = PowerWsEditor
window.PowerEditor = PowerEditor